package com.haohan.jingyuan.common.exception;

import com.haohan.jingyuan.gateway.dto.GwResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.beans.TypeMismatchException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.JsonMappingException;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 获取当前请求路径
     *
     * @return 请求路径
     */
    private String getRequestPath() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            return request.getRequestURI();
        }
        return null;
    }

    /**
     * 处理业务异常。
     *
     * @param e 业务异常实例
     * @return 标准错误响应（HTTP 400）
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public GwResponse<Void> handleBusinessException(BusinessException e) {
        log.warn("业务异常: {}", e.getMessage());
        GwResponse<Void> response = GwResponse.error(e.getCode(), e.getMessage());
        response.setPath(getRequestPath());
        return response;
    }

    /**
     * 处理参数校验异常。
     *
     * @param e 参数校验异常实例
     * @return 标准错误响应（HTTP 400），包含首个字段错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public GwResponse<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = "参数校验失败";
        if (e.getBindingResult().getFieldError() != null) {
            message = e.getBindingResult().getFieldError().getDefaultMessage();
        }
        log.warn("参数校验异常: {}", message);
        GwResponse<Void> response = GwResponse.error(400, message);
        response.setPath(getRequestPath());
        return response;
    }

    /**
     * 处理HTTP请求方法不支持异常。
     *
     * @param e HTTP请求方法不支持异常实例
     * @return 标准错误响应（HTTP 405），包含明确的错误信息
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public GwResponse<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        String method = e.getMethod();
        String[] supportedMethods = e.getSupportedMethods();
        String supportedMethodsStr = supportedMethods != null && supportedMethods.length > 0 
                ? String.join(", ", supportedMethods) 
                : "未知";
        String message = String.format("请求方法 '%s' 不支持，该接口仅支持 %s 方法", method, supportedMethodsStr);
        log.warn("HTTP请求方法不支持异常: {} - {}", method, e.getMessage());
        GwResponse<Void> response = GwResponse.error(405, message);
        response.setPath(getRequestPath());
        return response;
    }

    /**
     * 处理参数类型不匹配异常（包括日期格式错误）。
     *
     * @param e 参数类型不匹配异常实例
     * @return 标准错误响应（HTTP 400），包含明确的错误信息
     */
    @ExceptionHandler({MethodArgumentTypeMismatchException.class, TypeMismatchException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public GwResponse<Void> handleTypeMismatchException(Exception e) {
        String message = "参数类型错误";
        String fieldName = null;
        
        if (e instanceof MethodArgumentTypeMismatchException) {
            MethodArgumentTypeMismatchException ex = (MethodArgumentTypeMismatchException) e;
            fieldName = ex.getName();
            Class<?> requiredType = ex.getRequiredType();
            
            // 如果是日期类型，给出明确的格式要求
            if (requiredType != null && (requiredType == java.util.Date.class || requiredType.getName().equals("java.util.Date"))) {
                message = String.format("参数 '%s' 日期格式错误，必须为 yyyy-MM-dd HH:mm:ss 格式，例如：2025-11-30 00:00:00", fieldName);
            } else {
                message = String.format("参数 '%s' 类型错误，期望类型：%s", fieldName, requiredType != null ? requiredType.getSimpleName() : "未知");
            }
        } else if (e instanceof TypeMismatchException) {
            TypeMismatchException ex = (TypeMismatchException) e;
            fieldName = ex.getPropertyName();
            Class<?> requiredType = ex.getRequiredType();
            
            // 如果是日期类型，给出明确的格式要求
            if (requiredType != null && (requiredType == java.util.Date.class || requiredType.getName().equals("java.util.Date"))) {
                message = String.format("参数 '%s' 日期格式错误，必须为 yyyy-MM-dd HH:mm:ss 格式，例如：2025-11-30 00:00:00", fieldName);
            } else {
                message = String.format("参数 '%s' 类型错误，期望类型：%s", fieldName, requiredType != null ? requiredType.getSimpleName() : "未知");
            }
        }
        
        log.warn("参数类型不匹配异常: {} - {}", fieldName, message);
        GwResponse<Void> response = GwResponse.error(400, message);
        response.setPath(getRequestPath());
        return response;
    }

    /**
     * 处理JSON格式错误异常（包括日期格式错误）。
     *
     * @param e JSON格式错误异常实例
     * @return 标准错误响应（HTTP 400），包含明确的错误信息
     */
    @ExceptionHandler(InvalidFormatException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public GwResponse<Void> handleInvalidFormatException(InvalidFormatException e) {
        String message = "JSON格式错误";
        String fieldName = null;
        
        // 获取字段路径
        if (e.getPath() != null && !e.getPath().isEmpty()) {
            JsonMappingException.Reference ref = e.getPath().get(e.getPath().size() - 1);
            fieldName = ref.getFieldName();
        }
        
        // 检查是否是日期类型
        Class<?> targetType = e.getTargetType();
        if (targetType != null && (targetType == java.util.Date.class || targetType.getName().equals("java.util.Date"))) {
            String inputValue = e.getValue() != null ? e.getValue().toString() : "null";
            message = String.format("参数 '%s' 日期格式错误，必须为 yyyy-MM-dd HH:mm:ss 格式，例如：2025-11-30 00:00:00，当前值：%s", 
                    fieldName != null ? fieldName : "未知", inputValue);
        } else {
            message = String.format("参数 '%s' 格式错误，期望类型：%s", 
                    fieldName != null ? fieldName : "未知", targetType != null ? targetType.getSimpleName() : "未知");
        }
        
        log.warn("JSON格式错误异常: {} - {}", fieldName, message);
        GwResponse<Void> response = GwResponse.error(400, message);
        response.setPath(getRequestPath());
        return response;
    }

    /**
     * 处理系统异常（未知异常）。
     *
     * @param e 异常实例
     * @return 标准错误响应（HTTP 500）
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public GwResponse<Void> handleException(Exception e) {
        log.error("系统异常", e);
        GwResponse<Void> response = GwResponse.error("系统内部错误");
        response.setPath(getRequestPath());
        return response;
    }
}